package filesystem.client;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Clase que gerencia os comandos passados ao cliente
 *
 * Lê da entrada padrão os comandos e seus respectivos
 * argumentos os executando em seguida
 */
public class ClientOperator extends Thread{
	private final static String	OP_CREATE	= "create";
	private final static String	OP_DELETE	= "delete";
	private final static String	OP_READ		= "read";
	private final static String	OP_WRITE	= "write";
	private final static String	OP_EXIT		= "exit"; 
	
	/**
	 * Verifica se a String de entrada é um número.
	 * 
	 * @param input String a ser verificada.
	 * @return true, caso seja um número, false, caso contrário.
	 */
	public static boolean isNumeric(String input){
		  try {
		    Integer.parseInt(input);
		    return true;
		  }
		  catch (NumberFormatException e) {
		    return false;
		  }
		}
	
	private Client client;
	private BufferedReader in; 
	private BufferedOutputStream output;

	/**
	 * Inicializa o tratador de comandos
	 * 
	 * @param client Objeto para o qual serão repassados os comandos
	 * @param path Caminho do arquivo para o armazenamento dos tempos das operações.
	 */
	public ClientOperator(Client client, String path){
		this.client = client;
		this.in = new BufferedReader(new InputStreamReader(System.in));
		try {
			this.output = new BufferedOutputStream(new FileOutputStream(path));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Inicializa a requesição de um create.
	 */
	private void handleCreate(){
		String path;
		try {
			while ((path = in.readLine()) != null && path.length() != 0){
				System.out.println("Creating file: " + path);
				long time = System.currentTimeMillis();
				this.client.Create(path);
				time = System.currentTimeMillis() - time;
				this.output.write(("Create time: " + time + "\n").getBytes());
			}
		} catch (IOException e){
			e.printStackTrace();
		}
	}

	/**
	 * Inicializa a requesição de um delete.
	 */
	private void handleDelete() {
		String path;
		try {
			while ((path = in.readLine()) != null && path.length() != 0){
				System.out.println("Deleting file: " + path);
				long time = System.currentTimeMillis();
				this.client.Delete(path);
				time = System.currentTimeMillis() - time;
				this.output.write(("Delete time: " + time + "\n").getBytes());
			}
		} catch (IOException e){
			e.printStackTrace();
		}
	}

	/**
	 * Inicializa a requesição de um read.
	 */
	private void handleRead(){
		String path;
		try {
			while ((path = in.readLine()) != null && path.length() != 0){
				System.out.println("Reading file: " + path);
				long time = System.currentTimeMillis();
				this.client.Read(path);
				time = System.currentTimeMillis() - time;
				this.output.write(("Read time: " + time + "\n").getBytes());
			}
		} catch (IOException e){
			e.printStackTrace();
		}
	}

	/**
	 * Inicializa a requesição de um write.
	 */
	private void handleWrite() {
		String path;
		try {
			while ((path = in.readLine()) != null && path.length() != 0){
				System.out.println("Writing file: " + path);
				long time = System.currentTimeMillis();
				this.client.Write(path);
				time = System.currentTimeMillis() - time;
				this.output.write(("Write time: " + time + "\n").getBytes());
			}
		} catch (IOException e){
			e.printStackTrace();
		}
	}

	/**
	 * Ouve a entrada padrão e analiza os comandos.
	 */
	@Override
	public void run(){
		String input;
		try {
			while ((input = in.readLine()) != null && input.length() != 0){
				if(isNumeric(input)){
					do{
						int sleep = Integer.parseInt(input);
						try {
							Thread.sleep(sleep);
						} catch (InterruptedException e){
							e.printStackTrace();
						}
					}while ((input = in.readLine()) != null && input.length() != 0 && isNumeric(input));
				}else if(input.equals(ClientOperator.OP_CREATE)){
					this.handleCreate();
				}else if(input.equals(ClientOperator.OP_READ)){
					this.handleRead();
				}else if(input.equals(ClientOperator.OP_DELETE)){
					this.handleDelete();
				}else if(input.equals(ClientOperator.OP_WRITE)){
					this.handleWrite();
				}else if(input.equals(ClientOperator.OP_EXIT)){
					this.output.close();
					System.exit(0);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
